package com.idealighter.game.games.errentexaspoker.manager;

import com.google.inject.Inject;
import com.google.inject.Singleton;

import com.idealighter.game.dictionary.dic.ErrentexaporkerRoomDic;
import com.idealighter.game.dictionary.dic.ErrentexaporkerRoomTypeDic;
import com.idealighter.game.dictionary.domain.ErrentexaporkerRoomDomain;
import com.idealighter.game.gamehall.dto.MemInfo;
import com.idealighter.game.games.common.AbstractRoom;
import com.idealighter.game.games.common.AbstractSeat;
import com.idealighter.game.games.common.AbstractTable;
import com.idealighter.game.games.common.RoomState;
import com.idealighter.game.games.errentexaspoker.dto.PlayerBillInfo;
import com.idealighter.game.games.errentexaspoker.dto.PlayerCards;
import com.idealighter.game.games.errentexaspoker.dto.RoomInfo;
import com.idealighter.game.games.errentexaspoker.dto.RoomTypeDetailInfo;
import com.idealighter.game.games.errentexaspoker.message.ResBanlanceMsg;
import com.idealighter.game.games.errentexaspoker.message.ResBetMsg;
import com.idealighter.game.games.errentexaspoker.message.ResBillMsg;
import com.idealighter.game.games.errentexaspoker.message.ResChipsChangeMsg;
import com.idealighter.game.games.errentexaspoker.message.ResDealCardsMsg;
import com.idealighter.game.games.errentexaspoker.message.ResEnterRoomMsg;
import com.idealighter.game.games.errentexaspoker.message.ResEnterTableMsg;
import com.idealighter.game.games.errentexaspoker.message.ResExitRoomMsg;
import com.idealighter.game.games.errentexaspoker.message.ResExitTableMsg;
import com.idealighter.game.games.errentexaspoker.message.ResFastEnterTableMsg;
import com.idealighter.game.games.errentexaspoker.message.ResGameHallMsg;
import com.idealighter.game.games.errentexaspoker.message.ResHiddenCardsMsg;
import com.idealighter.game.games.errentexaspoker.message.ResLightCardMsg;
import com.idealighter.game.games.errentexaspoker.message.ResNextSeatMsg;
import com.idealighter.game.games.errentexaspoker.message.ResOtherPlayerMsg;
import com.idealighter.game.games.errentexaspoker.message.ResReadyMsg;
import com.idealighter.game.games.errentexaspoker.message.ResTurnOverMsg;
import com.idealighter.game.games.errentexaspoker.message.ResWinMsg;
import com.idealighter.game.games.errentexaspoker.struct.ErrenTexapokerRoom;
import com.idealighter.game.games.texaspoker.struct.cards.Card;
import com.idealighter.game.message.core.ResMessage;
import com.idealighter.game.player.manager.PlayerMgr;
import com.idealighter.game.player.manager.PlayerMsgWriter;
import com.idealighter.game.player.struct.Player;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 德州消息管理 .
 */
@Singleton
public class ErrenTexapokerMsgMgr {

  @Inject
  private PlayerMsgWriter msgWriter;
  @Inject
  private ErrenTexapokerDataMgr dataMgr;
  @Inject
  private ErrentexaporkerRoomDic roomDic;
  @Inject
  private ErrentexaporkerRoomTypeDic roomTypeDic;
  @Inject
  private PlayerMgr playerMgr;

  private static final Logger LOG = LoggerFactory.getLogger(ErrenTexapokerMsgMgr.class);

  // private ListSortUtil listSortUtil =
  // ApplicationContext.getBean(ListSortUtil.class);

  /**
   * 进入大厅-返回房间数据.
   * 
   * @param player 玩家.
   */
  public void sendGameHallMsg(Player player) {
    ResGameHallMsg msg = new ResGameHallMsg();

    Collection<ErrenTexapokerRoom> rooms = dataMgr.getRooms().values();
    for (ErrenTexapokerRoom room : rooms) {
      ErrentexaporkerRoomDomain roomDom = roomDic.map().get(room.getId().intValue());
      if (roomDom.getIsActive() != 1) {
        continue;
      }

      RoomTypeDetailInfo roomTypeDetailInfo = new RoomTypeDetailInfo();

      roomTypeDetailInfo.setType(roomDom.getType());
      roomTypeDetailInfo.setTypeName(roomTypeDic.map().get(roomDom.getType()).getTypeName());

      RoomInfo roomInfo = new RoomInfo();
      roomInfo.setRoomId(room.getId().intValue());
      roomInfo.setName(roomDom.getName());
      roomInfo.setType(roomDom.getType());
      roomInfo.setMaxNum(roomDom.getMaxNum());
      roomInfo.setFree(roomDom.getFree());
      roomInfo.setGeneral(roomDom.getGeneral());
      roomInfo.setCrowded(roomDom.getCrowded());
      roomInfo.setLower(roomDom.getLower());
      roomInfo.setUpper(roomDom.getUpper());
      roomInfo.setProportionGold(roomDom.getProportionGold());
      roomInfo.setProportionChips(roomDom.getProportionChips());
      roomInfo.setTabble(roomDom.getTable());
      roomInfo.setMaxOne(roomDom.getMaxOne());
      roomInfo.setMinOne(roomDom.getMinOne());
      roomInfo.setAfee(roomDom.getAfee());
      roomInfo.setInType(roomDom.getInType());
      roomInfo.setPlayerNum(room.getPlayers().size());
      roomInfo.setStatus(roomStatus(room).desc);
      roomInfo.setDisplayNames(roomDom.getDisplays());
      roomInfo.setPlaceHolder(roomDom.getPlaceHolder());
      roomTypeDetailInfo.getRooms().add(roomInfo);

      msg.getRoomTypes().add(roomTypeDetailInfo);
    }

    msgWriter.writeMsg(player, msg);
  }

  /**
   * 房间状态，空闲,普通,拥挤,爆满.
   * 
   * @param room .
   * @return
   */
  private RoomState roomStatus(ErrenTexapokerRoom room) {
    int playersNum = room.getPlayers().size();
    ErrentexaporkerRoomDomain roomDom = roomDic.map().get(room.getId().intValue());

    if (playersNum < roomDom.getMaxNum() * roomDom.getFree() / 100) {
      return RoomState.IDLE;
    } else if (playersNum < roomDom.getMaxNum() * roomDom.getGeneral() / 100) {
      return RoomState.GENERAL;
    } else if (playersNum < roomDom.getMaxNum() * roomDom.getCrowded() / 100) {
      return RoomState.CROWD;
    } else {
      return RoomState.FULL;
    }
  }

  /**
   * 发送进入桌子消息.
   * 
   * @param player 玩家.
   */
  public void sendEnterRoomMsg(Player player) {
    ResEnterRoomMsg msg = new ResEnterRoomMsg();
    for (AbstractTable table : player.curRoom.tables()) {
      msg.getTables().add(table.tableInfo());
    }
    msg.setMembers(player.curRoom.memInfos());
    msgWriter.writeMsg(player, msg);
  }

  /**
   * 发送进入桌子消息.
   * 
   * @param player 玩家.
   * @param table .
   */
  public void sendEnterTableMsg(Player player, AbstractTable table) {
    ResEnterTableMsg msg = new ResEnterTableMsg();
    AbstractRoom room = table.room();
    List<MemInfo> mems = new ArrayList<>();
    for (Long playerId : table.players()) {
      mems.add(room.memInfo(playerId));
    }
    msg.setMems(mems);
    msgWriter.writeMsg(player, msg);
  }

  /**
   * 给其他玩家发送我进入房间的消息.
   *
   * @param table .
   * @param seat 座位信息.
   */

  public void sendOhterPlayer(ErrenTexapokerRoom.Table table, ErrenTexapokerRoom.Table.Seat seat) {
    ResOtherPlayerMsg msg = new ResOtherPlayerMsg();
    // msg.setSeat(seat.seatInfo());
    msg.setMem(seat.table.room.memInfo(seat.getPlayerId()));
    for (ErrenTexapokerRoom.Table.Seat seat1 : table.seats) {
      if (seat.getOrder() != seat1.getOrder()) {
        msgWriter.writeMsg(seat1.getPlayerId(), msg);
      }
    }
  }

  /**
   * 向同桌的玩家发送该座位的玩家已经准备好.
   * 
   * @param seat 座位信息.
   * @param res 0:成功,1:重复准备
   */
  public void sendReadyMsg(ErrenTexapokerRoom.Table.Seat seat, int res) {
    ResReadyMsg msg = new ResReadyMsg();
    msg.setOrder(seat.getOrder());
    msg.setRes(res);
    sendTablePlayersMsg(seat.table, msg);
  }

  /**
   * 向同桌的每个玩家发送自己的牌消息.
   * 
   * @param table .
   */
  public void sendDealCardsMsg(ErrenTexapokerRoom.Table table) {
    for (ErrenTexapokerRoom.Table.Seat seat : table.seats) {
      if (seat.getPlayerId() == 0) {
        continue;
      }
      ResDealCardsMsg msg = new ResDealCardsMsg();
      for (Card card : seat.cards.subList(0, 2)) {
        // CardInfo info = new CardInfo();
        // info.setSuit(card.getSuit().toString());
        // info.setNumber(card.getNumber().getPower());
        msg.getCards().add(card.cardId());
      }
      msg.setLandlordOrder(table.landlordOrder);
      msg.setSmallBind(table.smallBind);
      msg.setBinBind(table.bigBind);
      msgWriter.writeMsg(seat.getPlayerId(), msg);
      if (seat.isWin == 1) {
        sendWinMsg(seat.getPlayerId(), seat.getOrder());
      }
    }

  }

  /**
   * 返回下注结果 . ->广播所有人.
   *
   * @param table .
   * @param bet .
   */
  public void sendBetMsg(ErrenTexapokerRoom.Table table, int type, long bet, int order) {
    ResBetMsg msg = new ResBetMsg();
    msg.setOrder(order);
    msg.setBet(bet);
    msg.setBetType(type);
    for (ErrenTexapokerRoom.Table.Seat seat : table.seats) {
      if (seat.getPlayerId() == 0) {
        continue;
      }
      msgWriter.writeMsg(seat.getPlayerId(), msg);
    }
  }

  /**
   * 通知下一个玩家下注 . ->所有玩家都能看到 .
   */
  public void sendNextSeatBet(ErrenTexapokerRoom.Table table, int order, long raiseBet,
      long maxBet) {
    ResNextSeatMsg msg = new ResNextSeatMsg();
    LOG.info("order [{}], raiseBet[{}], maxBet [{}] ", order, raiseBet, maxBet);
    msg.setOrder(order);
    msg.setRaisetBet(raiseBet);
    msg.setCurMaxBet(maxBet);
    table.seats.stream().filter(seat -> seat.getPlayerId() > 0).forEach(seat -> {
      msgWriter.writeMsg(seat.getPlayerId(), msg);
    });
  }

  /**
   * 发公共牌.
   * 
   * @param table .
   */
  public void sendCommonCard(ErrenTexapokerRoom.Table table, int state, List<Card> cardList,
      int isNeedInfo) {
    ResHiddenCardsMsg msg = new ResHiddenCardsMsg();
    msg.setIsNeedInfo(isNeedInfo);
    for (Card card : cardList) {
      // CardInfo info = new CardInfo();
      // info.setSuit(card.getSuit().toString());
      // info.setNumber(card.getNumber().getPower());
      msg.getCards().add(card.cardId());
    }
    for (ErrenTexapokerRoom.Table.Seat seat : table.seats) {
      if (seat.getPlayerId() == 0) {
        continue;
      }
      msgWriter.writeMsg(seat.getPlayerId(), msg);
      // sendTurnOver(seat.playerId, state);
    }
  }

  /**
   * 通知客户端该轮次结束 .
   */
  public void sendTurnOver(long playerId, int state) {
    ResTurnOverMsg msg = new ResTurnOverMsg();
    msg.setState(state);
    msgWriter.writeMsg(playerId, msg);
  }

  /**
   * 发送座位上的玩家退出牌桌消息.
   * 
   * @param seat 座位信息.
   */
  public void sendExitTableMsg(ErrenTexapokerRoom.Table.Seat seat) {
    ResExitTableMsg msg = new ResExitTableMsg();
    msg.setSeatInfo(seat.seatInfo());
    sendTablePlayersMsg(seat.table, msg);
  }

  /**
   * 向同桌的玩家(包括自己)发送消息.
   * 
   * @param table .
   * @param msg .
   */
  public void sendTablePlayersMsg(ErrenTexapokerRoom.Table table, ResMessage msg) {
    List<? extends AbstractSeat> seats = table.seats();
    for (int i = 0; i < seats.size(); i++) {
      AbstractSeat seat = seats.get(i);
      long playerId = seat.getPlayerId();
      if (playerId > 0) {
        msgWriter.writeMsg(playerId, msg);
      }
    }
  }

  /**
   * 向同房间的玩家(包括自己)发送消息.
   * 
   * @param room .
   * @param msg .
   */
  public void sendRoomPlayersMsg(ErrenTexapokerRoom room, ResMessage msg) {

    room.getPlayers().forEach(player -> msgWriter.writeMsg(player, msg));
  }

  /**
   * 发送结算结果给玩家.
   *
   * @param table .
   * @param type .
   */

  public void sendBanlance(ErrenTexapokerRoom.Table table, int type) {
    ResBanlanceMsg msg = new ResBanlanceMsg();
    msg.setType(type);
    List<ErrenTexapokerRoom.Table.Seat> seatList = new ArrayList<>();
    sortBillInfo(table, seatList);
    seatList.stream().filter(seat -> seat.getPlayerId() > 0 && seat.billBet > 0).forEach(seat -> {
      PlayerBillInfo info = new PlayerBillInfo();
      info.setOrder(seat.getOrder());
      info.setBet(seat.billBet);
      msg.getBillInfo().add(info);
    });
    table.seats.stream().filter(seat -> seat.getPlayerId() > 0 && seat.isFold == false)
        .forEach(seat -> {
          if (seat.getPlayerId() > 0 && !seat.cards.isEmpty()) {
            PlayerCards cards = new PlayerCards();
            cards.setOrder(seat.getOrder());
            for (Card card : seat.cards.subList(0, 2)) {
              cards.getCards().add(card.cardId());
            }
            msg.getCards().add(cards);
          }
        });
    for (ErrenTexapokerRoom.Table.Seat seat : table.seats) {
      if (seat.getPlayerId() > 0) {
        msgWriter.writeMsg(seat.getPlayerId(), msg);
      }
    }
  }

  /**
   * 排序.
   *
   * @param table .
   */
  private void sortBillInfo(ErrenTexapokerRoom.Table table,
      List<ErrenTexapokerRoom.Table.Seat> seatList) {
    seatList.addAll(table.seats.stream().filter(seat -> seat.getPlayerId() > 0 && seat.billBet > 0)
        .collect(Collectors.toList()));

    Collections.sort(seatList, new Comparator<ErrenTexapokerRoom.Table.Seat>() {
      @Override
      public int compare(ErrenTexapokerRoom.Table.Seat o1, ErrenTexapokerRoom.Table.Seat o2) {
        return o2.getPower() - o1.getPower();
      }
    });
  }

  /**
   * 筹码变化消息.
   *
   * @param seat 座位信息.
   */
  public void sendChipsChangeMsg(ErrenTexapokerRoom.Table.Seat seat) {
    ResChipsChangeMsg msg = new ResChipsChangeMsg();
    msg.setChips(seat.getTotalChips());
    msg.setOrder(seat.getOrder());
    msgWriter.writeMsg(seat.getPlayerId(), msg);
    sendOtherChipsChangeMsg(seat, msg); // 发送筹码变化给其他玩家

  }

  /**
   * 筹码变化需要通知给同座其他玩家(不包括自己) . ->让其他玩家看到.
   *
   * @param seat 座位信息.
   * @param msg .
   */
  public void sendOtherChipsChangeMsg(ErrenTexapokerRoom.Table.Seat seat, ResMessage msg) {
    seat.table.seats.stream()
        .filter(seat1 -> seat1.getPlayerId() > 0 && seat1.getPlayerId() != seat.getPlayerId())
        .forEach(seat1 -> msgWriter.writeMsg(seat1.getPlayerId(), msg));
  }

  /**
   * 发送结算消息.
   * 
   * @param seat 座位信息.
   * @param res 0:成功,1:没有可结算筹码 -》玩家单个的请求的结算
   */
  public void sendBillMsg(ErrenTexapokerRoom.Table.Seat seat, int res) {
    ResBillMsg msg = new ResBillMsg();
    msg.setRes(res);
    msgWriter.writeMsg(seat.getPlayerId(), msg);
  }

  // /**
  // * 返回退出大厅结果 .
  // *
  // * @param player 玩家.
  // * @param res
  // */
  // public void snedExitGameHall(Player player, int res) {
  // ResExitGameHallMsg msg = new ResExitGameHallMsg();
  // msg.setResult(res);
  // msgWriter.writeMsg(player, msg);
  // }

  /**
   * 发送亮牌信息.
   *
   * @param table .
   * @param seat 座位信息.
   */
  public void sendLighCard(ErrenTexapokerRoom.Table table, ErrenTexapokerRoom.Table.Seat seat) {
    ResLightCardMsg msg = new ResLightCardMsg();
    for (Card card : seat.cards) {
      msg.getCards().add(card.cardId());
    }
    for (ErrenTexapokerRoom.Table.Seat seat1 : table.seats) {
      msgWriter.writeMsg(seat1.getPlayerId(), msg);
    }
  }

  /**
   * 发送获胜消息.
   *
   * @param playerId 玩家id.
   * @param order .
   */
  public void sendWinMsg(long playerId, int order) {
    ResWinMsg msg = new ResWinMsg();
    msg.setOrder(order);
    if (playerMgr.getPlayer(playerId).playerBo().getRegisterType() == 0) {
      msgWriter.writeMsg(playerId, msg);
    }
  }

  /**
   * 发送退出房间消息.
   * 
   * @param player 玩家.
   * @param res 0:退出成功,1:在牌桌中退出失败
   */
  public void sendExitRoomMsg(Player player, int res) {
    ResExitRoomMsg msg = new ResExitRoomMsg();
    msg.setRes(res);
    msgWriter.writeMsg(player, msg);
  }

  /**
   * 发送快速进入结果消息.
   * 
   * @param player 玩家.
   * @param res 0:成功,1:没有空位置
   */
  public void sendFastEnterTableMsg(Player player, int res) {
    ResFastEnterTableMsg msg = new ResFastEnterTableMsg();
    msg.setRes(res);
    msgWriter.writeMsg(player, msg);
  }
}
